{
 "cells": [
  {
   "cell_type": "markdown",
   "source": [
    "##### Copyright 2019 The TensorFlow Authors."
   ],
   "metadata": {
    "id": "SB93Ge748VQs"
   }
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "source": [
    "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\r\n",
    "# you may not use this file except in compliance with the License.\r\n",
    "# You may obtain a copy of the License at\r\n",
    "#\r\n",
    "# https://www.apache.org/licenses/LICENSE-2.0\r\n",
    "#\r\n",
    "# Unless required by applicable law or agreed to in writing, software\r\n",
    "# distributed under the License is distributed on an \"AS IS\" BASIS,\r\n",
    "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n",
    "# See the License for the specific language governing permissions and\r\n",
    "# limitations under the License."
   ],
   "outputs": [],
   "metadata": {
    "cellView": "form",
    "id": "0sK8X2O9bTlz"
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "# 开始使用 TensorBoard\n",
    "\n",
    "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
    "  <td>\n",
    "    <a target=\"_blank\" href=\"https://tensorflow.google.cn/tensorboard/get_started\"><img src=\"https://tensorflow.google.cn/images/tf_logo_32px.png\" />View on TensorFlow.org</a>\n",
    "  </td>\n",
    "  <td>\n",
    "    <a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs-l10n/blob/master/site/zh-cn/tensorboard/get_started.ipynb\"><img src=\"https://tensorflow.google.cn/images/colab_logo_32px.png\" />Run in Google Colab</a>\n",
    "  </td>\n",
    "  <td>\n",
    "    <a target=\"_blank\" href=\"https://github.com/tensorflow/docs-l10n/blob/master/site/zh-cn/tensorboard/get_started.ipynb\"><img src=\"https://tensorflow.google.cn/images/GitHub-Mark-32px.png\" />View source on GitHub</a>\n",
    "  </td>\n",
    "  <td>\n",
    "    <a href=\"https://storage.googleapis.com/tensorflow_docs/docs-l10n/site/zh-cn/tensorboard/get_started.ipynb\"><img src=\"https://tensorflow.google.cn/images/download_logo_32px.png\" />下载此 notebook</a>\n",
    "  </td>\n",
    "</table>"
   ],
   "metadata": {
    "id": "HEYuO5NFwDK9"
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "在机器学习中，要改进模型的某些参数，您通常需要对其进行衡量。TensorBoard 是用于提供机器学习工作流程期间所需的测量和可视化的工具。 它使您能够跟踪实验指标，例如损失和准确性，可视化模型图，将嵌入物投影到较低维度的空间等等。\n",
    "\n",
    "本快速入门将展示如何快速使用 TensorBoard 。该网站上的其余指南提供了有关特定功能的更多详细信息，此处未包括其中的许多功能。"
   ],
   "metadata": {
    "id": "56V5oun18ZdZ"
   }
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "source": [
    "try:\r\n",
    "  # %tensorflow_version only exists in Colab.\r\n",
    "  %tensorflow_version 2.x\r\n",
    "except Exception:\r\n",
    "  pass\r\n",
    "\r\n",
    "# Load the TensorBoard notebook extension\r\n",
    "%load_ext tensorboard"
   ],
   "outputs": [],
   "metadata": {
    "id": "6B95Hb6YVgPZ"
   }
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "source": [
    "# 来学习一下可视化工具吧，先导入包库\r\n",
    "import tensorflow as tf\r\n",
    "import datetime\r\n",
    "\r\n",
    "print(tf.__version__)"
   ],
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "2.5.0\n"
     ]
    }
   ],
   "metadata": {
    "id": "_wqSAZExy6xV"
   }
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "source": [
    "# 清除之前的logs\r\n",
    "# Clear any logs from previous runs\r\n",
    "!rm -rf ./logs/ "
   ],
   "outputs": [
    {
     "output_type": "stream",
     "name": "stderr",
     "text": [
      "'rm' �����ڲ����ⲿ���Ҳ���ǿ����еĳ���\n",
      "���������ļ���\n"
     ]
    }
   ],
   "metadata": {
    "id": "Ao7fJW1Pyiza"
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "在本例中使用 [MNIST](https://en.wikipedia.org/wiki/MNIST_database) 数据集。接下来编写一个函数对数据进行标准化，同时创建一个简单的Keras模型使图像分为10类。"
   ],
   "metadata": {
    "id": "z5pr9vuHVgXY"
   }
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "source": [
    "# 使用mnist来进行演示\r\n",
    "# 导入数据集并归一化\r\n",
    "mnist = tf.keras.datasets.mnist\r\n",
    "\r\n",
    "(x_train, y_train),(x_test, y_test) = mnist.load_data()\r\n",
    "x_train, x_test = x_train / 255.0, x_test / 255.0\r\n",
    "# 建立模型\r\n",
    "# 先打平,过一个线性层,加一个dropout,再过一个线性层softmax激活输出\r\n",
    "def create_model():\r\n",
    "  return tf.keras.models.Sequential([\r\n",
    "    tf.keras.layers.Flatten(input_shape=(28, 28)),\r\n",
    "    tf.keras.layers.Dense(512, activation='relu'),\r\n",
    "    tf.keras.layers.Dropout(0.2),\r\n",
    "    tf.keras.layers.Dense(10, activation='softmax')\r\n",
    "  ])"
   ],
   "outputs": [],
   "metadata": {
    "id": "j-DHsby18cot"
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "## 通过 Keras Model.fit() 使用 TensorBoard"
   ],
   "metadata": {
    "id": "XKUjdIoV87um"
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "当使用 Keras's [Model.fit()](https://tensorflow.google.cn/api_docs/python/tf/keras/models/Model#fit) 函数进行训练时, 添加 `tf.keras.callback.TensorBoard` 回调可确保创建和存储日志.另外，在每个时期启用 `histogram_freq=1` 的直方图计算功能（默认情况下处于关闭状态）\n",
    "\n",
    "将日志放在带有时间戳的子目录中，以便轻松选择不同的训练运行。"
   ],
   "metadata": {
    "id": "8CL_lxdn8-Sv"
   }
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "source": [
    "# 生成模型\r\n",
    "model = create_model()\r\n",
    "# 看看模型的样子\r\n",
    "print(model.summary())\r\n",
    "# 编译模型,使用adam优化器,稀疏分类交叉熵（这里说明我们的标签没有进行one-hot编码）\r\n",
    "model.compile(optimizer='adam',\r\n",
    "              loss='sparse_categorical_crossentropy',\r\n",
    "              metrics=['accuracy'])\r\n",
    "# 日志的目录就是当前目录下的：logs/fit/<time_now>(\"%Y%m%d-%H%M%S\")\r\n",
    "# 我来用\r\n",
    "log_dir=\"logs/fit/\" + datetime.datetime.now().strftime(\"%Y%m%d-%H%M%S\")\r\n",
    "# 使用callback方法就可以实现再fit过程中，储存日志了，直方图=1\r\n",
    "tensorboard_callback = tf.keras.callbacks.TensorBoard(log_dir=log_dir, histogram_freq=1)\r\n",
    "# 进行训练，5个epoche，还有callbacks的参数\r\n",
    "model.fit(x=x_train, \r\n",
    "          y=y_train, \r\n",
    "          epochs=5, \r\n",
    "          validation_data=(x_test, y_test), \r\n",
    "          callbacks=[tensorboard_callback])"
   ],
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "Model: \"sequential\"\n",
      "_________________________________________________________________\n",
      "Layer (type)                 Output Shape              Param #   \n",
      "=================================================================\n",
      "flatten (Flatten)            (None, 784)               0         \n",
      "_________________________________________________________________\n",
      "dense (Dense)                (None, 512)               401920    \n",
      "_________________________________________________________________\n",
      "dropout (Dropout)            (None, 512)               0         \n",
      "_________________________________________________________________\n",
      "dense_1 (Dense)              (None, 10)                5130      \n",
      "=================================================================\n",
      "Total params: 407,050\n",
      "Trainable params: 407,050\n",
      "Non-trainable params: 0\n",
      "_________________________________________________________________\n",
      "None\n",
      "Epoch 1/5\n",
      "1875/1875 [==============================] - 14s 6ms/step - loss: 0.2204 - accuracy: 0.9346 - val_loss: 0.0977 - val_accuracy: 0.9687\n",
      "Epoch 2/5\n",
      "1875/1875 [==============================] - 7s 4ms/step - loss: 0.0974 - accuracy: 0.9699 - val_loss: 0.0734 - val_accuracy: 0.9773\n",
      "Epoch 3/5\n",
      "1875/1875 [==============================] - 7s 4ms/step - loss: 0.0685 - accuracy: 0.9782 - val_loss: 0.0681 - val_accuracy: 0.9795\n",
      "Epoch 4/5\n",
      "1875/1875 [==============================] - 7s 4ms/step - loss: 0.0532 - accuracy: 0.9832 - val_loss: 0.0704 - val_accuracy: 0.9762\n",
      "Epoch 5/5\n",
      "1875/1875 [==============================] - 6s 3ms/step - loss: 0.0450 - accuracy: 0.9851 - val_loss: 0.0682 - val_accuracy: 0.9802\n"
     ]
    },
    {
     "output_type": "execute_result",
     "data": {
      "text/plain": [
       "<tensorflow.python.keras.callbacks.History at 0x2551efbb0d0>"
      ]
     },
     "metadata": {},
     "execution_count": 5
    }
   ],
   "metadata": {
    "id": "WAQThq539CEJ"
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "通过命令行 （command） 或在 notebook 体验中启动 TensorBoard ，这两个接口通常是相同的。 在 notebooks, 使用 `%tensorboard` 命令。 在命令行中， 运行不带“％”的相同命令。"
   ],
   "metadata": {
    "id": "asjGpmD09dRl"
   }
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "source": [
    "%tensorboard --logdir logs/fit\r\n",
    "# 这个要在终端里面运行"
   ],
   "outputs": [
    {
     "output_type": "display_data",
     "data": {
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ],
      "text/html": [
       "\n",
       "      <iframe id=\"tensorboard-frame-4ce6b0cf022a42f5\" width=\"100%\" height=\"800\" frameborder=\"0\">\n",
       "      </iframe>\n",
       "      <script>\n",
       "        (function() {\n",
       "          const frame = document.getElementById(\"tensorboard-frame-4ce6b0cf022a42f5\");\n",
       "          const url = new URL(\"/\", window.location);\n",
       "          const port = 6006;\n",
       "          if (port) {\n",
       "            url.port = port;\n",
       "          }\n",
       "          frame.src = url;\n",
       "        })();\n",
       "      </script>\n",
       "    "
      ]
     },
     "metadata": {}
    }
   ],
   "metadata": {
    "id": "A4UKgTLb9fKI"
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "<img class=\"tfo-display-only-on-site\" src=\"https://github.com/tensorflow/tensorboard/blob/master/docs/images/quickstart_model_fit.png?raw=1\"/>"
   ],
   "metadata": {
    "id": "MCsoUNb6YhGc"
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "简要概述所显示的仪表板（顶部导航栏中的选项卡）：\n",
    "\n",
    "* **Scalars** 显示损失和指标在每个时期如何变化。 您还可以使用它来跟踪训练速度，学习率和其他标量值。\n",
    "* **Graphs** 可帮助您可视化模型。 在这种情况下，将显示层的Keras图，这可以帮助您确保正确构建。 \n",
    "* **Distributions** 和 **Histograms** 显示张量随时间的分布。 这对于可视化权重和偏差并验证它们是否以预期的方式变化很有用。\n",
    "\n",
    "当您记录其他类型的数据时，会自动启用其他 TensorBoard 插件。 例如，使用 Keras TensorBoard 回调还可以记录图像和嵌入。 您可以通过单击右上角的“inactive”下拉列表来查看 TensorBoard 中还有哪些其他插件。"
   ],
   "metadata": {
    "id": "Gi4PaRm39of2"
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "# 以上是在keras的API中使用tensorboard,下面是用tensorflow的API来使用tensorboard\r\n",
    "## 通过其他方法使用 TensorBoard"
   ],
   "metadata": {
    "id": "nB718NOH95yG"
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "用以下方法训练时，例如 [`tf.GradientTape()`](https://tensorflow.google.cn/api_docs/python/tf/GradientTape), 会使用 `tf.summary` 记录所需的信息。\n",
    "\n",
    "使用与上述相同的数据集，但将其转换为 `tf.data.Dataset` 以利用批处理功能："
   ],
   "metadata": {
    "id": "IKNt0nWs-Ekt"
   }
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "source": [
    "# 当使用tensorflow训练时，也可以使用tensorboard，这里是tensorflow的方法\r\n",
    "# 设置数据集，打乱数据，划分batch\r\n",
    "train_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train))\r\n",
    "test_dataset = tf.data.Dataset.from_tensor_slices((x_test, y_test))\r\n",
    "\r\n",
    "train_dataset = train_dataset.shuffle(60000).batch(64)\r\n",
    "test_dataset = test_dataset.batch(64)"
   ],
   "outputs": [],
   "metadata": {
    "id": "nnHx4DsMezy1"
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "训练代码遵循 [advanced quickstart](https://tensorflow.google.cn/tutorials/quickstart/advanced) 教程，但显示了如何将 log 记录到 TensorBoard 。 首先选择损失和优化器："
   ],
   "metadata": {
    "id": "SzpmTmJafJ10"
   }
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "source": [
    "# 定义损失函数和优化器\r\n",
    "loss_object = tf.keras.losses.SparseCategoricalCrossentropy()\r\n",
    "optimizer = tf.keras.optimizers.Adam()"
   ],
   "outputs": [],
   "metadata": {
    "id": "H2Y5-aPbAANs"
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "创建可用于在训练期间累积值并在任何时候记录的有状态指标："
   ],
   "metadata": {
    "id": "cKhIIDj9Hbfy"
   }
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "source": [
    "# Define our metrics\r\n",
    "# 定义精度\r\n",
    "train_loss = tf.keras.metrics.Mean('train_loss', dtype=tf.float32)\r\n",
    "train_accuracy = tf.keras.metrics.SparseCategoricalAccuracy('train_accuracy')\r\n",
    "test_loss = tf.keras.metrics.Mean('test_loss', dtype=tf.float32)\r\n",
    "test_accuracy = tf.keras.metrics.SparseCategoricalAccuracy('test_accuracy')"
   ],
   "outputs": [],
   "metadata": {
    "id": "jD0tEWrgH0TL"
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "定义训练和测试代码："
   ],
   "metadata": {
    "id": "szw_KrgOg-OT"
   }
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "source": [
    "# 实际上tensorflow的训练和torch的API差不多\r\n",
    "def train_step(model, optimizer, x_train, y_train):\r\n",
    "  with tf.GradientTape() as tape:\r\n",
    "    predictions = model(x_train, training=True)\r\n",
    "    loss = loss_object(y_train, predictions)\r\n",
    "  grads = tape.gradient(loss, model.trainable_variables)\r\n",
    "  optimizer.apply_gradients(zip(grads, model.trainable_variables))\r\n",
    "\r\n",
    "  train_loss(loss)\r\n",
    "  train_accuracy(y_train, predictions)\r\n",
    "\r\n",
    "def test_step(model, x_test, y_test):\r\n",
    "  predictions = model(x_test)\r\n",
    "  loss = loss_object(y_test, predictions)\r\n",
    "\r\n",
    "  test_loss(loss)\r\n",
    "  test_accuracy(y_test, predictions)"
   ],
   "outputs": [],
   "metadata": {
    "id": "TTWcJO35IJgK"
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "设置摘要编写器，以将摘要写到另一个日志目录中的磁盘上："
   ],
   "metadata": {
    "id": "nucPZBKPJR3A"
   }
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "source": [
    "current_time = datetime.datetime.now().strftime(\"%Y%m%d-%H%M%S\")\r\n",
    "train_log_dir = 'logs/gradient_tape/' + current_time + '/train'\r\n",
    "test_log_dir = 'logs/gradient_tape/' + current_time + '/test'\r\n",
    "train_summary_writer = tf.summary.create_file_writer(train_log_dir)\r\n",
    "test_summary_writer = tf.summary.create_file_writer(test_log_dir)"
   ],
   "outputs": [],
   "metadata": {
    "id": "3Qp-exmbWf4w"
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "开始训练，在 summary writers 的范围内，在训练/测试期间使用 `tf.summary.scalar()` 记录指标（损失和准确性），以将摘要写入磁盘。 您可以控制要记录的指标以及记录的频率。 其他的 `tf.summary` 函数可以记录其他类型的数据。"
   ],
   "metadata": {
    "id": "qgUJgDdKWUKF"
   }
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "source": [
    "# 重置我们的模型\r\n",
    "model = create_model() # reset our model\r\n",
    "\r\n",
    "EPOCHS = 5\r\n",
    "\r\n",
    "for epoch in range(EPOCHS):\r\n",
    "  for (x_train, y_train) in train_dataset:\r\n",
    "    train_step(model, optimizer, x_train, y_train)\r\n",
    "  with train_summary_writer.as_default():\r\n",
    "    tf.summary.scalar('loss', train_loss.result(), step=epoch)\r\n",
    "    tf.summary.scalar('accuracy', train_accuracy.result(), step=epoch)\r\n",
    "\r\n",
    "  for (x_test, y_test) in test_dataset:\r\n",
    "    test_step(model, x_test, y_test)\r\n",
    "  with test_summary_writer.as_default():\r\n",
    "    tf.summary.scalar('loss', test_loss.result(), step=epoch)\r\n",
    "    tf.summary.scalar('accuracy', test_accuracy.result(), step=epoch)\r\n",
    "  \r\n",
    "  template = 'Epoch {}, Loss: {}, Accuracy: {}, Test Loss: {}, Test Accuracy: {}'\r\n",
    "  print (template.format(epoch+1,\r\n",
    "                         train_loss.result(), \r\n",
    "                         train_accuracy.result()*100,\r\n",
    "                         test_loss.result(), \r\n",
    "                         test_accuracy.result()*100))\r\n",
    "\r\n",
    "  # Reset metrics every epoch\r\n",
    "  train_loss.reset_states()\r\n",
    "  test_loss.reset_states()\r\n",
    "  train_accuracy.reset_states()\r\n",
    "  test_accuracy.reset_states()"
   ],
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "Epoch 1, Loss: 0.24346032738685608, Accuracy: 92.92500305175781, Test Loss: 0.11757567524909973, Test Accuracy: 96.45999908447266\n",
      "Epoch 2, Loss: 0.10456385463476181, Accuracy: 96.8550033569336, Test Loss: 0.08368917554616928, Test Accuracy: 97.40999603271484\n",
      "Epoch 3, Loss: 0.07242301851511002, Accuracy: 97.80166625976562, Test Loss: 0.08085247874259949, Test Accuracy: 97.54999542236328\n",
      "Epoch 4, Loss: 0.055363986641168594, Accuracy: 98.2366714477539, Test Loss: 0.06866170465946198, Test Accuracy: 97.75\n",
      "Epoch 5, Loss: 0.04406122863292694, Accuracy: 98.54000091552734, Test Loss: 0.06736263632774353, Test Accuracy: 97.97000122070312\n"
     ]
    }
   ],
   "metadata": {
    "id": "odWvHPpKJvb_"
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "再次打开 TensorBoard，这次将其指向新的日志目录。 我们也可以启动 TensorBoard 来监视训练进度。"
   ],
   "metadata": {
    "id": "JikosQ84fzcA"
   }
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "source": [
    "%tensorboard --logdir logs/gradient_tape"
   ],
   "outputs": [
    {
     "output_type": "display_data",
     "data": {
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ],
      "text/html": [
       "\n",
       "      <iframe id=\"tensorboard-frame-397c0f2d80e90ba5\" width=\"100%\" height=\"800\" frameborder=\"0\">\n",
       "      </iframe>\n",
       "      <script>\n",
       "        (function() {\n",
       "          const frame = document.getElementById(\"tensorboard-frame-397c0f2d80e90ba5\");\n",
       "          const url = new URL(\"/\", window.location);\n",
       "          const port = 6006;\n",
       "          if (port) {\n",
       "            url.port = port;\n",
       "          }\n",
       "          frame.src = url;\n",
       "        })();\n",
       "      </script>\n",
       "    "
      ]
     },
     "metadata": {}
    }
   ],
   "metadata": {
    "id": "-Iue509kgOyE"
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "<img class=\"tfo-display-only-on-site\" src=\"https://github.com/tensorflow/tensorboard/blob/master/docs/images/quickstart_gradient_tape.png?raw=1\"/>"
   ],
   "metadata": {
    "id": "NVpnilhEgQXk"
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "您现在已经了解了如何通过 Keras 回调和通过 `tf.summary` 使用 TensorBoard 来实现更多自定义场景。"
   ],
   "metadata": {
    "id": "ozbwXgPIkCKV"
   }
  }
 ],
 "metadata": {
  "colab": {
   "collapsed_sections": [],
   "name": "get_started.ipynb",
   "toc_visible": true
  },
  "kernelspec": {
   "name": "python3",
   "display_name": "Python 3.8.0 64-bit ('tf2': conda)"
  },
  "language_info": {
   "name": "python",
   "version": "3.8.0",
   "mimetype": "text/x-python",
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "pygments_lexer": "ipython3",
   "nbconvert_exporter": "python",
   "file_extension": ".py"
  },
  "interpreter": {
   "hash": "36da4b91dd2581054531180cdc4c2c0091d575643278a8e66e43a4111cad88e6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}